home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
001
/
pibt40s5.arc
/
RECEIVX1.MOD
< prev
next >
Wrap
Text File
|
1987-07-18
|
48KB
|
1,325 lines
(*----------------------------------------------------------------------*)
(* Receive_Xmodem_File --- Download file using XMODEM *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Xmodem_File( Use_CRC : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Xmodem_File *)
(* *)
(* Purpose: Downloads file from remote host using XMODEM *)
(* protocol. *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Xmodem_File( Use_CRC ); *)
(* *)
(* Use_CRC --- TRUE to use Cyclic redundancy check version *)
(* of XMODEM; FALSE to use Checksum version. *)
(* *)
(* Remarks: *)
(* *)
(* The transmission parameters are automatically set to: *)
(* *)
(* Current baud rate, 8 bits, No parity, 1 stop *)
(* *)
(* and then they are automatically restored to the previous *)
(* values when the transfer is complete. *)
(* *)
(* This code actually controls file reception using any of the *)
(* Xmodem-based protocols: Xmodem, Modem7, Telink, and Ymodem. *)
(* *)
(* Calls: KeyPressed *)
(* Async_Send *)
(* Async_Receive *)
(* Async_Receive_With_TimeOut *)
(* Async_Purge_Buffer *)
(* Update_Xmodem_Receive_Display *)
(* Display_Receive_Error *)
(* Receive_Xmodem_Sector *)
(* Receive_Telink_Header *)
(* Receive_Ymodem_Header *)
(* Wait_For_SOH *)
(* Set_File_Date_And_Time *)
(* Draw_Menu_Frame *)
(* Open_Receiving_File *)
(* Write_File_Handle *)
(* Close_File_Handle *)
(* *)
(*----------------------------------------------------------------------*)
CONST
XOFF_Delay = 250 (* WXModem XOFF delay time *);
WXmodem_Flush = 4 (* Blocks to flush when error *);
SEALink_Flush = 6 (* Blocks to flush when error *);
VAR
Sector_Count : INTEGER (* Sector count -- no wrap at 255 *);
Sector_Comp : BYTE (* Complement of current sector # *);
Sector_Prev : BYTE (* Previous sector number *);
I : INTEGER (* Loop index *);
Error_Count : INTEGER (* # of errors encountered *);
Ch : INTEGER (* Character read from COM port *);
Error_Flag : BOOLEAN (* IF an error is found *);
Initial_Ch : INTEGER (* Initial character *);
Sector_Length : INTEGER (* Sector Length *);
Sector_Prev1 : BYTE (* Previous sector + 1 *);
BlockL_Errors : INTEGER (* Counts block length errors *);
SOH_Errors : INTEGER (* Counts SOH errors *);
BlockN_Errors : INTEGER (* Counts block number errors *);
Comple_Errors : INTEGER (* Counts complement errors *);
TimeOut_Errors: INTEGER (* Counts timeout errors *);
Resend_Errors : INTEGER (* Counts resend block errors *);
CRC_Errors : INTEGER (* Counts checksum/crc errors *);
Effective_Rate: REAL (* Effective baud rate of transfer *);
CRC_Tries : INTEGER (* Initial CRC tries *);
WXM_Tries : INTEGER (* Initial WXModem tries *);
SOH_Time : INTEGER (* Seconds to wait for SOH *);
RFile_Size : REAL (* Actual file size *);
RFile_Date : REAL (* File date/time *);
File_Date : INTEGER (* MS DOS encoded file date *);
File_Time : INTEGER (* MS DOS encoded file time *);
RFile_Name : AnyStr (* Received file name, Ymodem *);
Truncate_File : BOOLEAN (* TRUE to trunc. file to exact size *);
RFile_Open : BOOLEAN (* TRUE if receiving file opened *);
XFile_Byte : FILE OF BYTE (* For truncating received file *);
OK_Transfer : BOOLEAN (* If transfer OK *);
Block_Zero : BOOLEAN (* If block 0 encountered *);
RFile_Size_2 : REAL (* File size from totalling sectors *);
TName : ShortStr (* Transfer type *);
Display_Time : BOOLEAN (* Display time remaining for trans. *);
Time_To_Send : REAL (* Time in seconds to transfer file *);
Start_Time : REAL (* Starting time of transfer *);
End_Time : REAL (* Ending time of transfer *);
Time_Per_Block: REAL (* Time for one block *);
Blocks_To_Get : REAL (* Number of blocks *);
Write_Count : INTEGER (* Number of bytes to write *);
Err : INTEGER (* Error flag for handle I/O *);
(* Write buffer pointer *)
Write_Buffer : File_Handle_Buffer_Ptr;
Buffer_Pos : INTEGER (* Current buffer position *);
Buffer_Length : INTEGER (* Buffer length *);
Use_CRC_2 : BOOLEAN (* TRUE to use CRC method *);
Menu_Title : AnyStr (* Menu title *);
Alt_R_Pressed : BOOLEAN (* TRUE if Alt-R cancelled download *);
Long_Buffer : BOOLEAN (* TRUE if separate buffer used *);
Kbd_Ch : CHAR (* Character entered from keyboard *);
Full_File_Name: AnyStr (* Full file name of file to receive *);
Dup_Block : BOOLEAN (* TRUE if duplicate block error *);
BS_Flag : BOOLEAN (* Swallows up duplicate block *);
W_Count : INTEGER (* Count to write *);
Do_ACKs : BOOLEAN (* TRUE to do ACKs *);
Block_Start_Set : SET OF ^A..^Z (* Set of legal block start chars *);
SVal : STRING[10] (* For debugging conversions *);
Flush_Count : INTEGER (* Count of blocks to flush if bad *);
Save_XonXoff : BOOLEAN (* Saves XON/XOFF status *);
Err_Mess : AnyStr (* Error message *);
(*----------------------------------------------------------------------*)
(* Open_Receiving_File --- open file to receive download *)
(*----------------------------------------------------------------------*)
PROCEDURE Open_Receiving_File;
VAR
Err : INTEGER;
B : BOOLEAN;
Local_Save : Saved_Screen_Ptr;
BEGIN (* Open_Receiving_File *)
(* Check if file name given yet. *)
(* If not, prompt for it. *)
IF FileName = '' THEN
BEGIN
B := Do_Status_Time;
Do_Status_Time := FALSE;
Save_Partial_Screen( Local_Save, 1, Max_Screen_Line,
Max_Screen_Col, Max_Screen_Line );
Window( 1, 1, Max_Screen_Col, Max_Screen_Line );
GoToXY( 1 , Max_Screen_Line );
WRITE('Enter file name to receive download: ');
ClrEol;
Read_Edited_String( FileName );
Restore_Screen( Local_Save );
Do_Status_Time := B;
END;
(* Append download directory name *)
(* if necessary. *)
IF ( POS( '\' , FileName ) = 0 ) AND
( POS( ':' , FileName ) = 0 ) THEN
Full_File_Name := Download_Dir_Path + FileName
ELSE
Full_File_Name := FileName;
(* Open reception file *)
IF ( NOT RFile_Open ) THEN
BEGIN
Err := Create_File_Handle( Full_File_Name,
Attribute_None, XFile_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
GoToXY( 25 , 10 );
WRITE('Cannot open reception file, receive cancelled.');
ClrEol;
Write_Log('Cannot open reception file, receive cancelled.',
TRUE, FALSE);
DELAY( One_Second_Delay );
Stop_Receive := TRUE;
END
ELSE
RFile_Open := TRUE;
END;
IF Rfile_Open THEN
Write_Log('Receiving file ' + Full_File_Name, TRUE, FALSE );
END (* Open_Receiving_File *);
(*----------------------------------------------------------------------*)
(* Initialize_Receive_Display --- Set up display of Xmodem reception *)
(*----------------------------------------------------------------------*)
PROCEDURE Initialize_Receive_Display;
BEGIN (* Initialize_Receive_Display *)
TextColor( Menu_Text_Color_2 );
GoToXY( 1 , 1 );
WRITE(' Blocks received :');
ClrEol;
GoToXY( 1 , 2 );
WRITE(' Block length errors :');
ClrEol;
GoToXY( 1 , 3 );
WRITE(' SOH errors :');
ClrEol;
GoToXY( 1 , 4 );
WRITE(' Block number errors :');
ClrEol;
GoToXY( 1 , 5 );
WRITE(' Complement errors :');
ClrEol;
GoToXY( 1 , 6 );
WRITE(' Timeout errors :');
ClrEol;
GoToXY( 1 , 7 );
WRITE(' Resend block errors :');
ClrEol;
GoToXY( 1 , 8 );
IF ( NOT Use_CRC ) THEN
WRITE(' Checksum errors :')
ELSE
WRITE(' CRC errors :');
ClrEol;
GoToXY( 1 , 9 );
IF Display_Time THEN
WRITE(' Approx. time left :')
ELSE
WRITE(' ');
ClrEol;
GoToXY( 1 , 10 );
WRITE (' Last status message :');
ClrEol;
TextColor( Menu_Text_Color );
END (* Initialize_Receive_Display *);
(*----------------------------------------------------------------------*)
(* Flip_Display_Status --- turn status display on/off *)
(*----------------------------------------------------------------------*)
PROCEDURE Flip_Display_Status;
BEGIN (* Flip_Display_Status *)
CASE Display_Status OF
TRUE: BEGIN
(* Indicate no display *)
Display_Status := FALSE;
(* Remove XMODEM window *)
Restore_Screen( Saved_Screen );
(* Remove batch transfer window *)
Restore_Screen( Batch_Screen_Ptr );
(* Turn cursor back on *)
CursorOn;
END;
FALSE: BEGIN
(* Indicate display will be done *)
Display_Status := TRUE;
(* Turn cursor off *)
CursorOff;
(* Initialize batch transfer display *)
(* if needed. *)
IF ( NOT Single_File_Protocol[Transfer_Protocol] ) THEN
Display_Batch_Window;
(* Save screen image *)
Save_Screen( Saved_Screen );
(* Initialize display window *)
Draw_Menu_Frame( 15, 10, 78, 22, Menu_Frame_Color,
Menu_Title_Color,
Menu_Text_Color, Menu_Title );
Window( 16, 11, 77, 21 );
(* Set up titles *)
Initialize_Receive_Display;
END;
END (* CASE *);
END (* Flip_Display_Status *);
(*----------------------------------------------------------------------*)
(* Check_Keyboard_Input --- Check for keyboard input *)
(*----------------------------------------------------------------------*)
PROCEDURE Check_Keyboard_Input;
BEGIN (* Check_Keyboard_Input *)
(* Check for keyboard input -- Alt_R *)
(* cancels transfer. *)
WHILE KeyPressed DO
BEGIN
READ( Kbd, Kbd_Ch );
IF ( Kbd_Ch = CHR( ESC ) ) AND KeyPressed THEN
BEGIN
READ( Kbd, Kbd_Ch );
CASE ORD( Kbd_Ch ) OF
Alt_R : Alt_R_Pressed := TRUE;
Shift_Tab : Flip_Display_Status;
ELSE Handle_Function_Key( Kbd_Ch );
END (* CASE *);
Stop_Receive := Stop_Receive OR Alt_R_Pressed;
END;
END;
END (* Check_Keyboard_Input *);
(*----------------------------------------------------------------------*)
(* Update_Xmodem_Receive_Display --- Update display of Xmodem reception *)
(*----------------------------------------------------------------------*)
PROCEDURE Update_Xmodem_Receive_Display;
BEGIN (* Update_Xmodem_Receive_Display *)
GoToXY( 25 , 1 );
WRITE( Sector_Count );
GoToXY( 35 , 1 );
WRITE( Sector_Count SHR 3, 'K' );
GoToXY( 25 , 2 );
WRITE(BlockL_Errors);
GoToXY( 25 , 3 );
WRITE(SOH_Errors);
GoToXY( 25 , 4 );
WRITE(BlockN_Errors);
GoToXY( 25 , 5 );
WRITE(Comple_Errors);
GoToXY( 25 , 6 );
WRITE(TimeOut_Errors);
GoToXY( 25 , 7 );
WRITE(Resend_Errors);
GoToXY( 25 , 8 );
WRITE(CRC_Errors);
IF Display_Time THEN
BEGIN
GoToXY( 25 , 9 );
WRITE( TimeString( Time_To_Send , Military_Time ) );
END;
END (* Update_Xmodem_Receive_Display *);
(*----------------------------------------------------------------------*)
(* Display_Receive_Error --- Display XMODEM reception error *)
(*----------------------------------------------------------------------*)
PROCEDURE Display_Receive_Error( Err_Text: AnyStr );
VAR
S: STRING[10];
BEGIN (* Display_Receive_Error *)
IF ( NOT Display_Status ) THEN
Flip_Display_Status;
STR( Sector_Count , S );
Err_Mess := Err_Text + ' around block ' + S;
GoToXY( 25 , 10 );
WRITE(Err_Mess);
ClrEol;
Write_Log( Err_Mess, TRUE, FALSE );
Error_Flag := TRUE;
END (* Display_Receive_Error *);
(*----------------------------------------------------------------------*)
(* WXModem_Receive_With_TimeOut --- Get character from port for WXModem *)
(*----------------------------------------------------------------------*)
PROCEDURE WXModem_Receive_With_TimeOut( VAR Ch : INTEGER );
(* STRUCTURED *) CONST
Special_Chars : SET OF BYTE = [DLE,SYN,XON,XOFF];
BEGIN (* WXModem_Receive_With_TimeOut *)
Async_Receive_With_TimeOut( Xmodem_Char_Wait , Ch );
IF Do_WXModem THEN
IF ( Ch = DLE ) THEN
BEGIN
IF ( Ch IN Special_Chars ) THEN
BEGIN
Async_Receive_With_TimeOut( Xmodem_Char_Wait , Ch );
IF ( Ch <> TimeOut ) THEN
Ch := Ch XOR 64;
END
END
ELSE
IF ( Ch = SYN ) THEN
Ch := TimeOut;
END (* WXModem_Receive_With_TimeOut *);
(*----------------------------------------------------------------------*)
(* Xmodem_Receive_With_TimeOut --- Get character from port *)
(*----------------------------------------------------------------------*)
PROCEDURE XModem_Receive_With_TimeOut( VAR Ch : INTEGER );
BEGIN (* XModem_Receive_With_TimeOut *)
Async_Receive_With_TimeOut( Xmodem_Char_Wait , Ch );
(* Check for buffer overflow *)
(* if not doing ACKs *)
IF ( NOT Do_Acks ) THEN
IF ( Async_Buffer_Used = Async_Buffer_High ) THEN
BEGIN
IF ( NOT Async_Xoff_Sent ) THEN
BEGIN
Async_Send( CHR( XOFF ) );
Async_Xoff_Sent := TRUE;
END
END
ELSE
IF ( Async_Buffer_Used = Async_Buffer_High_2 ) THEN
BEGIN
Async_Send( CHR( XOFF ) );
Async_Xoff_Sent := TRUE;
END;
END (* XModem_Receive_With_TimeOut *);
(*----------------------------------------------------------------------*)
(* Receive_Xmodem_Sector --- Get sector using XMODEM *)
(*----------------------------------------------------------------------*)
FUNCTION Receive_Xmodem_Sector( Use_CRC : BOOLEAN ) : BOOLEAN;
(*----------------------------------------------------------------------*)
(* *)
(* Function: Receive_Xmodem_Sector *)
(* *)
(* Purpose: Gets one sector using XMODEM protocol. *)
(* *)
(* Calling Sequence: *)
(* *)
(* OK_Get := Receive_Xmodem_Sector( Use_CRC : BOOLEAN ) *)
(* : BOOLEAN; *)
(* *)
(* Use_CRC --- TRUE to use Cyclic redundancy check version *)
(* of XMODEM; FALSE to use Checksum version. *)
(* OK_Get --- TRUE if sector received correctly *)
(* *)
(* Calls: Async_Send *)
(* Async_Receive_With_TimeOut *)
(* Display_Receive_Error *)
(* Print_Spooled_File *)
(* *)
(*----------------------------------------------------------------------*)
VAR
CRC : INTEGER;
Checksum : INTEGER;
I : INTEGER;
Error_Fl : BYTE;
Receive_OK : BOOLEAN;
Debug_Sect : ARRAY[1..128] OF CHAR ABSOLUTE Sector_Data;
BEGIN (* Receive_Xmodem_Sector *)
(* Clear async error flags *)
Receive_OK := Async_Line_Error( Error_Fl );
(* Pick up sector data, calculate *)
(* checksum or CRC *)
Receive_Xmodem_Sector := FALSE;
Receive_OK := FALSE;
Checksum := 0;
CRC := 0;
(* Sector length is 128 for usual *)
(* Xmodem or Telink; is 1024 for *)
(* Ymodem. *)
FOR I := 1 TO Sector_Length DO
BEGIN
(* Print character from spooled file *)
IF Print_Spooling THEN
Print_Spooled_File;
(* Get next char from comm port *)
IF Do_WXModem THEN
WXModem_Receive_With_TimeOut( Ch )
ELSE
Xmodem_Receive_With_TimeOut( Ch );
(* Check for timeout *)
IF Ch = TimeOut THEN
BEGIN
Display_Receive_Error('Block length error');
BlockL_Errors := SUCC( BlockL_Errors );
EXIT;
END;
(* Store received character *)
Sector_Data[I] := Ch;
(* Update CRC or Checksum *)
IF Use_CRC THEN
BEGIN
CRC := SWAP( CRC ) XOR ORD( Ch );
CRC := CRC XOR ( LO( CRC ) SHR 4 );
CRC := CRC XOR ( SWAP( LO( CRC ) ) SHL 4 )
XOR ( LO( CRC ) SHL 5 );
END
ELSE
Checksum := ( Checksum + Ch ) AND 255;
END;
(* Now get trailing CRC or *)
(* checksum value. *)
IF Use_CRC THEN
BEGIN (* Receive CRC *)
(* Get first byte of CRC *)
IF Do_WXModem THEN
WXModem_Receive_With_TimeOut( Ch )
ELSE
Xmodem_Receive_With_TimeOut( Ch );
(* Check for timeout *)
IF Ch <> TimeOut THEN
BEGIN (* Byte CRC OK *)
(* Update CRC *)
CRC := SWAP( CRC ) XOR ORD( Ch );
CRC := CRC XOR ( LO( CRC ) SHR 4 );
CRC := CRC XOR ( SWAP( LO( CRC ) ) SHL 4 )
XOR ( LO( CRC ) SHL 5 );
(* Get second byte of CRC *)
IF Do_WXModem THEN
WXModem_Receive_With_TimeOut( Ch )
ELSE
Xmodem_Receive_With_TimeOut( Ch );
(* If not timeout, update CRC *)
(* and check if it is zero. *)
(* Zero CRC means OK sector. *)
IF Ch <> TimeOut THEN
BEGIN (* Byte 2 CRC OK *)
CRC := SWAP( CRC ) XOR ORD( Ch );
CRC := CRC XOR ( LO( CRC ) SHR 4 );
CRC := CRC XOR ( SWAP( LO( CRC ) ) SHL 4 )
XOR ( LO( CRC ) SHL 5 );
Receive_OK := ( CRC = 0 );
END (* Byte 2 CRC OK *)
ELSE
BEGIN (* Byte 2 CRC TimeOut *)
Display_Receive_Error('Block length error');
BlockL_Errors := SUCC( BlockL_Errors );
END (* Byte 2 CRC TimeOut *)
END (* Byte 1 CRC OK *)
ELSE
BEGIN (* Byte 1 CRC TimeOut *)
Display_Receive_Error('Block length error');
BlockL_Errors := SUCC( BlockL_Errors );
END (* Byte 1 CRC TimeOut *);
END (* Compute CRC *)
ELSE
BEGIN (* Receive Checksum *)
(* Read sector checksum, see if it matches *)
(* what we computed from sector read. *)
IF Do_WXModem THEN
WXModem_Receive_With_TimeOut( Ch )
ELSE
Xmodem_Receive_With_TimeOut( Ch );
Receive_OK := ( Checksum = Ch );
END (* Receive Checksum *);
Receive_Xmodem_Sector := Receive_OK AND
( NOT Async_Line_Error( Error_Fl ) );
END (* Receive_Xmodem_Sector *);
(*----------------------------------------------------------------------*)
(* Get_Unix_Style_Date --- Get date in Unix style *)
(*----------------------------------------------------------------------*)
PROCEDURE Get_Unix_Style_Date( Date : REAL;
VAR Year : INTEGER;
VAR Month : INTEGER;
VAR Day : INTEGER;
VAR Hour : INTEGER;
VAR Mins : INTEGER;
VAR Secs : INTEGER );
CONST
Secs_Per_Year = 31536000.0;
Secs_Per_Leap_Year = 31622400.0;
Secs_Per_Day = 86400.0;
Secs_Per_Hour = 3600.0;
Secs_Per_Minute = 60.0;
VAR
RDate : REAL;
T : REAL;
(* STRUCTURED *) CONST
Days_Per_Month : ARRAY[1..12] OF BYTE
= ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
BEGIN (* Get_Unix_Style_Date *)
Year := 1970;
Month := 1;
IF ( Transfer_Protocol <> SEALink ) THEN
RDate := Date - GMT_Difference * Secs_Per_Hour
ELSE
RDate := Date;
WHILE( RDate > 0.0 ) DO
BEGIN
IF ( Year MOD 4 ) = 0 THEN
T := Secs_Per_Leap_Year
ELSE
T := Secs_Per_Year;
RDate := RDate - T;
Year := Year + 1;
END;
RDate := RDate + T;
Year := Year - 1;
IF ( Year MOD 4 ) = 0 THEN
Days_Per_Month[2] := 29
ELSE
Days_Per_Month[2] := 28;
WHILE( RDate > 0.0 ) DO
BEGIN
T := Days_Per_Month[Month] * Secs_Per_Day;
RDate := RDate - T;
Month := Month + 1;
END;
RDate := RDate + T;
Month := Month - 1;
Day := TRUNC( INT( ( Rdate + Secs_Per_Day - 1 ) / Secs_Per_Day ) );
Rdate := Rdate - ( Day - 1 ) * Secs_Per_Day;
Hour := TRUNC( INT( Rdate / Secs_Per_Hour ) );
Rdate := Rdate - Hour * Secs_Per_Hour;
Mins := TRUNC( INT( Rdate / Secs_Per_Minute ) );
Secs := TRUNC( Rdate - Mins * Secs_Per_Minute );
END (* Get_Unix_Style_Date *);
(*----------------------------------------------------------------------*)
(* Receive_Telink_Header --- Get Telink block 0 header *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Telink_Header;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Telink_Header *)
(* *)
(* Purpose: Gets Telink header block 0 (filename+size+date) *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Telink_Header; *)
(* *)
(* Calls: *)
(* *)
(* Trim *)
(* Dir_Convert_Time *)
(* Dir_Convert_Date *)
(* Draw_Menu_Frame *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
CDate : STRING[8];
CTime : STRING[8];
Date : REAL;
Year : INTEGER;
Month : INTEGER;
Day : INTEGER;
Hour : INTEGER;
Mins : INTEGER;
Secs : INTEGER;
Debug_Sector_Data : PACKED ARRAY[1..44] OF CHAR ABSOLUTE Sector_Data;
BEGIN (* Receive_Telink_Header *)
RFile_Size := 0.0;
RFile_Name := '';
(* Get file size *)
FOR I := 4 DOWNTO 1 DO
RFile_Size := RFile_Size * 256.0 + Sector_Data[I];
Blocks_To_Get := ROUND( RFile_Size / 128.0 + 0.49 );
(* Get time/date *)
IF ( Transfer_Protocol = Telink ) THEN
BEGIN
File_Time := Sector_Data[6] SHL 8 OR Sector_Data[5];
File_Date := Sector_Data[8] SHL 8 OR Sector_Data[7];
END
ELSE
BEGIN
Date := ORD( Sector_Data[8] ) SHL 8 + ORD( Sector_Data[7] );
Date := 65536.0 * Date + ORD( Sector_Data[6] ) SHL 8 + ORD( Sector_Data[5] );
IF ( Date > 0.0 ) THEN
BEGIN
Get_Unix_Style_Date( Date, Year, Month, Day, Hour, Mins, Secs );
File_Time := Hour SHL 11 OR Mins SHL 5 OR ( Secs DIV 2 );
File_Date := MAX( Year - 1980 , 0 ) SHL 9 + Month SHL 5 + Day;
END;
END;
(* Get file name *)
FOR I := 9 TO 24 DO
IF Sector_Data[I] <> 0 THEN
RFile_Name := RFile_Name + CHR( Sector_Data[I] );
RFile_Name := TRIM( RFile_Name );
IF ( FileName = '' ) THEN
IF ( RFile_Name <> '' ) THEN
FileName := RFile_Name;
Draw_Menu_Frame( 15, 10, 78, 23, Menu_Frame_Color, Menu_Title_Color,
Menu_Text_Color,
'Receive file ' + FileName + ' using ' + Tname );
IF ( ( File_Date <> 0 ) AND ( File_Time <> 0 ) ) THEN
BEGIN
Dir_Convert_Time( File_Time, CTime );
Dir_Convert_Date( File_Date, CDate );
END
ELSE
BEGIN
CTime := '';
CDate := '';
END;
Draw_Menu_Frame( 15, 3, 78, 9, Menu_Frame_Color, Menu_Title_Color,
Menu_Text_Color, '' );
(* Headings for Telink information *)
Window( 16, 4, 77, 8 );
GoToXY( 1 , 1 );
TextColor( Menu_Text_Color_2 );
WRITE(' File name: ');
TextColor( Menu_Text_Color );
WRITE(FileName);
GoToXY( 1 , 2 );
TextColor( Menu_Text_Color_2 );
WRITE(' File Size in bytes: ');
TextColor( Menu_Text_Color );
WRITE(RFile_Size:8:0);
GoToXY( 1 , 3 );
TextColor( Menu_Text_Color_2 );
WRITE(' File Size in blocks: ');
TextColor( Menu_Text_Color );
WRITE(Blocks_To_Get:8:0);
GoToXY( 1 , 4 );
TextColor( Menu_Text_Color_2 );
WRITE(' File creation time: ');
TextColor( Menu_Text_Color );
WRITE( CTime );
GoToXY( 1 , 5 );
TextColor( Menu_Text_Color_2 );
WRITE(' File creation date: ');
TextColor( Menu_Text_Color );
WRITE( CDate );
(* Restore previous window *)
Window( 16, 11, 77, 21 );
IF RFile_Size > 0.0 THEN
BEGIN
Display_Time := TRUE;
Time_To_Send := Blocks_To_Get * ( Trans_Time_Val / Baud_Rate );
Time_Per_Block := Time_To_Send / Blocks_To_Get;
IF Display_Status THEN
Initialize_Receive_Display;
Truncate_File := TRUE;
END;
(* Handle SEALink file name *)
IF Do_SeaLink THEN
BEGIN
(* Prevent clobbers in host mode *)
IF Host_Mode THEN
IF ( Privilege <> 'S' ) THEN
Stop_Receive := Stop_Receive OR
Check_If_File_Exists( FileName , Download_Dir_Path );
(* If null file name, this means *)
(* end of SEALink batch, so quit. *)
IF LENGTH( RFile_Name ) = 0 THEN
BEGIN
Null_File_Name := TRUE;
EXIT;
END;
(* Open reception file *)
IF ( NOT Stop_Receive ) THEN
Open_Receiving_File;
END;
END (* Receive_Telink_Header *);
(*----------------------------------------------------------------------*)
(* Receive_Ymodem_Header --- Get Ymodem block 0 header *)
(*----------------------------------------------------------------------*)
PROCEDURE Receive_Ymodem_Header;
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Receive_Ymodem_Header *)
(* *)
(* Purpose: Gets Ymodem header block 0 (filename+size+date) *)
(* *)
(* Calling Sequence: *)
(* *)
(* Receive_Ymodem_Header *)
(* *)
(* Calls: *)
(* *)
(* Draw_Menu_Frame *)
(* Dir_Convert_Time *)
(* Dir_Convert_Date *)
(* Open_Receiving_File *)
(* *)
(*----------------------------------------------------------------------*)
VAR
I : INTEGER;
CTime : STRING[10];
CDate : STRING[10];
Year : INTEGER;
Month : INTEGER;
Day : INTEGER;
Hour : INTEGER;
Mins : INTEGER;
Secs : INTEGER;
BEGIN (* Receive_Ymodem_Header *)
RFile_Size := 0.0;
RFile_Date := 0.0;
RFile_Name := '';
File_Time := 0;
File_Date := 0;
(* Pick up file name *)
I := 1;
WHILE( Sector_Data[I] <> NUL ) AND ( Sector_Data[I] <> ORD(' ') ) DO
BEGIN
RFile_Name := RFile_Name + CHR( Sector_Data[I] );
I := SUCC( I );
END;
(* If null file name, this means *)
(* end of Ymodem batch, so quit. *)
IF LENGTH( RFile_Name ) = 0 THEN
BEGIN
Null_File_Name := TRUE;
EXIT;
END;
(* Pick up file size *)
I := SUCC( I );
WHILE( Sector_Data[I] <> NUL ) AND ( Sector_Data[I] <> ORD(' ') ) DO
BEGIN
RFile_Size := RFile_Size * 10.0 + ORD( Sector_Data[I] ) - ORD('0');
I := SUCC( I );
END;
I := SUCC( I );
WHILE( Sector_Data[I] <> NUL ) AND ( Sector_Data[I] <> ORD(' ') ) DO
BEGIN
RFile_Date := RFile_Date * 8.0 + ORD( Sector_Data[I] ) - ORD('0');
I := SUCC( I );
END;
IF RFile_Date > 0 THEN
BEGIN
Get_Unix_Style_Date( RFile_Date, Year, Month, Day, Hour, Mins, Secs );
File_Time := Hour SHL 11 OR Mins SHL 5 OR ( Secs DIV 2 );
File_Date := MAX( Year - 1980 , 0 ) SHL 9 + Month SHL 5 + Day;
Dir_Convert_Time( File_Time, CTime );
Dir_Convert_Date( File_Date, CDate );
END;
Draw_Menu_Frame( 15, 3, 78, 9, Menu_Frame_Color, Menu_Title_Color,
Menu_Text_Color,
'Receive file ' + RFile_Name + ' using ' + Tname );
(* Headings for Ymodem information *)
Window( 16, 4, 77, 8 );
GoToXY( 1 , 1 );
TextColor( Menu_Text_Color_2 );
WRITE(' File name: ');
TextColor( Menu_Text_Color );
WRITE(RFile_Name);
Blocks_To_Get := ROUND( RFile_Size / 128.0 + 0.49 );
IF RFile_Size > 0.0 THEN
BEGIN
GoToXY( 1 , 2 );
TextColor( Menu_Text_Color_2 );
WRITE(' File Size in bytes: ');
TextColor( Menu_Text_Color );
WRITE(RFile_Size:8:0);
GoToXY( 1 , 3 );
TextColor( Menu_Text_Color_2 );
WRITE(' File Size in blocks: ');
TextColor( Menu_Text_Color );
WRITE(Blocks_To_Get:8:0);
END;
IF File_Date > 0 THEN
BEGIN
GoToXY( 1 , 4 );
TextColor( Menu_Text_Color_2 );
WRITE(' File creation time: ');
TextColor( Menu_Text_Color );
WRITE( CTime );
GoToXY( 1 , 5 );
TextColor( Menu_Text_Color_2 );
WRITE(' File creation date: ');
TextColor( Menu_Text_Color );
WRITE( CDate );
END;
FileName := RFile_Name;
(* Restore previous window *)
Window( 16, 11, 77, 21 );
IF Rfile_Size > 0.0 THEN
BEGIN
Display_Time := TRUE;
Time_To_Send := Blocks_To_Get * ( Trans_Time_Val / Baud_Rate );
Time_Per_Block := Time_To_Send / Blocks_To_Get;
IF Display_Status THEN
Initialize_Receive_Display;
Truncate_File := ( RFile_Size > 0.0 );
END;
(* Prevent clobbers in host mode *)
IF Host_Mode THEN
IF ( Privilege <> 'S' ) THEN
Stop_Receive := Stop_Receive OR
Check_If_File_Exists( FileName , Download_Dir_Path );
(* Open reception file *)
IF ( NOT Stop_Receive ) THEN
Open_Receiving_File;
(* Post name in display window *)
IF ( RFile_Name = '' ) THEN
BEGIN
Window( 16, 4, 77, 8 );
GoToXY( 1 , 1 );
TextColor( Menu_Text_Color_2 );
WRITE(' File name: ');
TextColor( Menu_Text_Color );
WRITE(FileName);
Window( 16, 11, 77, 21 );
END;
(* Reset CRC counter *)
CRC_Tries := 0;
Use_CRC := TRUE;
END (* Receive_Ymodem_Header *);
(*----------------------------------------------------------------------*)
(* Wait_For_SOH --- Wait for start for start of XMODEM block *)
(*----------------------------------------------------------------------*)
PROCEDURE Wait_For_SOH( Wait_Time : INTEGER;
VAR Initial_Ch : INTEGER;
VAR Stop_Receive : BOOLEAN );
(*----------------------------------------------------------------------*)
(* *)
(* Procedure: Wait_For_SOH *)
(* *)
(* Purpose: Waits for SOH/STX/SYN initiating Xmodem block *)
(* *)
(* Calling Sequence: *)
(* *)
(* Wait_For_SOH( Wait_Time : INTEGER; *)
(* VAR Initial_Ch : INTEGER; *)
(* VAR Stop_Receive : BOOLEAN ); *)
(* *)
(* Wait_Time --- time to wait for character in seconds *)
(* Initial_Ch --- returned initial character *)
(* Stop_Receive --- TRUE if Alt-R hit to stop transfer *)
(* *)
(* Calls: *)
(* *)
(* Async_Receive_With_TimeOut *)
(* *)
(*----------------------------------------------------------------------*)
VAR
ITime : INTEGER;
SOH_Start_Time : REAL;
SOH_Char : CHAR;
BEGIN (* Wait_For_SOH *)
(* If already cancelled transfer, *)
(* don't look for more input! *)
Initial_Ch := TimeOut;
IF Stop_Receive THEN EXIT;
(* Look for start of Xmodem block *)
ITime := 0;
REPEAT
ITime := SUCC( ITime );
Initial_Ch := TimeOut;
SOH_Start_Time := TimeOfDayH;
REPEAT
IF Async_Receive( SOH_Char ) THEN
BEGIN
IF ( SOH_Char IN Block_Start_Set ) THEN
Initial_Ch := ORD( SOH_Char );
END;
UNTIL ( Initial_Ch <> TimeOut ) OR
( TimeDiffH( SOH_Start_Time , TimeOfDayH ) > 100.0 );
(* Check for keyboard input -- Alt_R *)
(* cancels transfer. *)
Check_Keyboard_Input;
(* Also stop transfer if carrier drops *)
IF Async_Carrier_Drop THEN
BEGIN
Stop_Receive := TRUE;
Initial_Ch := TimeOut;
END;
(* Print character from spooled file *)
IF Print_Spooling THEN
Print_Spooled_File;
UNTIL ( Stop_Receive OR
( ITime > Wait_Time ) OR
( Initial_Ch <> TimeOut ) );
END (* Wait_For_SOH *);
(*----------------------------------------------------------------------*)
(* Set_File_Date_And_Time --- set file date and time stamp *)
(*----------------------------------------------------------------------*)
PROCEDURE Set_File_Date_And_Time;
VAR
OLd_Time : INTEGER;
Old_Date : INTEGER;
Err : INTEGER;
File_Handle: INTEGER;
(*----------------------------------------------------------------------*)
PROCEDURE Set_File_Time_Error;
BEGIN (* Set_File_Time_Error *)
IF ( NOT Display_Status ) THEN
Flip_Display_Status;
GoToXY( 25 , 10 );
WRITE('Could not set date/time for file.');
ClrEol;
DELAY( One_Second_Delay );
END (* Set_File_Time_Error *);
(*----------------------------------------------------------------------*)
BEGIN (* Set_File_Date_And_Time *)
Err := Open_File_Handle( Full_File_Name, Access_Read_And_Write_Mode,
File_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
Set_File_Time_Error;
Write_Log('Cannot reopen file to set date/time', TRUE, FALSE );
Err := Close_File_Handle( File_Handle );
END
ELSE
BEGIN
Err := Dir_Set_File_Date_And_Time( File_Handle, File_Date,
File_Time );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
Set_File_Time_Error;
Write_Log('Cannot set date/time', TRUE, FALSE );
Err := Close_File_Handle( File_Handle );
END
ELSE
BEGIN
Err := Close_File_Handle( File_Handle );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) THEN
BEGIN
Set_File_Time_Error;
Write_Log('Cannot close file after date/time set', TRUE, FALSE );
END
END;
END;
END (* Set_File_Date_And_Time *);
(*----------------------------------------------------------------------*)
(* Write_File_Data --- Write received data to file *)
(*----------------------------------------------------------------------*)
PROCEDURE Write_File_Data;
PROCEDURE Do_Actual_Write( Write_Count: INTEGER );
BEGIN (* Do_Actual_Write *)
IF ( ( RFile_Size_2 + Write_Count ) > RFile_Size ) AND Truncate_File THEN
Write_Count := TRUNC( RFile_Size - Rfile_Size_2 );
W_Count := Write_Count;
(* Stop data reception for WXModem *)
IF Do_WXModem THEN
BEGIN
Async_Send( CHR( XOFF ) );
DELAY( XOFF_Delay );
END;
Err := Write_File_Handle( XFile_Handle, Write_Buffer^, Write_Count );
IF Do_WXModem THEN
Async_Send( CHR( XON ) );
IF ( Err <> 0 ) OR ( Int24Result <> 0 ) OR ( Write_Count <> W_Count ) THEN
BEGIN
IF ( NOT Display_Status ) THEN
Flip_Display_Status;
GoToXY( 25 , 10 );
WRITE('Error writing to disk, transfer cancelled.');
Write_Log('Error writing to disk.' , TRUE, FALSE );
ClrEol;
DELAY( One_Second_Delay );
Stop_Receive := TRUE;
END;
RFile_Size_2 := RFile_Size_2 + Write_Count;
END (* Do_Actual_Write *);
(*----------------------------------------------------------------------*)
BEGIN (* Write_File_Data *)
(* Write directly from sector *)
(* if not long buffer used *)
IF ( NOT Long_Buffer ) THEN
Do_Actual_Write( Sector_Length )
(* Store sector data in long *)
(* buffer and write file if *)
(* necessary. *)
ELSE
BEGIN
IF ( Buffer_Pos + Sector_Length ) > Buffer_Length THEN
BEGIN
Do_Actual_Write( Buffer_Pos );
Buffer_Pos := 0;
END;
MOVE( Sector_Data, Write_Buffer^[ Buffer_Pos + 1 ], Sector_Length );
Buffer_Pos := Buffer_Pos + Sector_Length;
END;
END (* Write_File_Data *);
(*----------------------------------------------------------------------*)
(* Cancel_Transfer --- Cancel transfer *)
(*----------------------------------------------------------------------*)
PROCEDURE Cancel_Transfer;
BEGIN (* Cancel_Transfer *)
(* Purge reception *)
Async_Purge_Buffer;
(* Send five cancels, then five *)
(* backspaces. *)
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( CAN ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Async_Send( CHR( BS ) );
Write_Log('Receive cancelled.' , TRUE, FALSE );
END (* Cancel_Transfer *);